package com.project.auth.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.project.auth.mapper.ProcessMapper;
import com.project.auth.model.process.Process;
import com.project.auth.model.process.ProcessRecord;
import com.project.auth.model.process.ProcessTemplate;
import com.project.auth.model.system.SysUser;
import com.project.auth.service.*;
import com.project.auth.vo.process.ApprovalVo;
import com.project.auth.vo.process.ProcessFormVo;
import com.project.auth.vo.process.ProcessQueryVo;
import com.project.auth.vo.process.ProcessVo;
import com.project.security.custom.LoginUserInfoHelper;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.EndEvent;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;

/**
 * @Description
 * @Author : XIAOMING
 * @create 2023/6/1 10:48
 */
@Service
public class ProcessServiceImpl extends ServiceImpl<ProcessMapper, Process> implements ProcessService {
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private ProcessTemplateService processTemplateService;
    @Autowired
    private ProcessRecordService processRecordService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private MessageService messageService;

    @Override
    public IPage<ProcessVo> selectPage(Page<ProcessVo> pageParam, ProcessQueryVo processQueryVo) {
        IPage<ProcessVo> pageList = baseMapper.selectPage(pageParam, processQueryVo);

        return pageList;
    }

    @Override
    public void deployByZip(String deployPath) {
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(deployPath);
        ZipInputStream zipInputStream = new ZipInputStream(inputStream);
        //部署
        Deployment deploy = repositoryService.createDeployment().addZipInputStream(zipInputStream).deploy();

        //System.out.println(deploy.getName());
    }

    /**
     * 启动流程
     *
     * @param formVo
     */
    @Override
    public void startUp(ProcessFormVo formVo) {
        //1.根据当前用户id获取用户信息
        SysUser user = sysUserService.getById(LoginUserInfoHelper.getUserId());
        //2.根据审批模板id查询模板信息
        ProcessTemplate template = processTemplateService.getById(formVo.getProcessTemplateId());
        //3.保存提交的审批信息到业务表，oa_process
        Process process = new Process();
        BeanUtils.copyProperties(formVo, process);
        process.setStatus(1);
        process.setProcessCode(System.currentTimeMillis() + "");
        process.setUserId(LoginUserInfoHelper.getUserId());
        process.setTitle(user.getName() + "发起" + template.getName() + "申请");
        baseMapper.insert(process);//插入数据
        //4.启动流程实例
        //4.1流程定义key
        String defineKey = template.getProcessDefinitionKey();
        //4.2业务key
        String businessKey = String.valueOf(process.getId());
        //4.3流程参数，form表单json数据，转换map集合
        String formValues = formVo.getFormValues();
        JSONObject jsonObject = JSON.parseObject(formValues);
        JSONObject formData = jsonObject.getJSONObject("formData");
        //遍历formData,封装map
        Map<String, Object> map = new HashMap<>();
        for (Map.Entry<String, Object> entry : formData.entrySet()) {
            map.put(entry.getKey(), entry.getValue());
        }
        //套一层map,将之前的map当作一个整体
        Map<String, Object> value = new HashMap<>();
        value.put("data", map);
        //启动流程实例
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(defineKey, businessKey, value);
        //5.查询下个审批人
        List<String> assigneeList = new ArrayList<>();
        List<Task> taskList = this.getCurrentTaskList(processInstance.getId());
        for (Task task : taskList) {
            String assigneeName = task.getAssignee();
            SysUser assigneeUser = sysUserService.getByUsername(assigneeName);
            String realName = assigneeUser.getName();
            assigneeList.add(realName);
            //6.发送推送消息
            messageService.pushPendingMessage(process.getId(), assigneeUser.getId(), task.getId());
        }
        process.setProcessInstanceId(processInstance.getId());
        process.setDescription("等待" + StringUtils.join(assigneeList.toArray(), ",") + "审批");
        //7.业务和流程进行关联
        baseMapper.updateById(process);
        //记录操作审批信息记录
        processRecordService.record(process.getId(), process.getStatus(), process.getDescription());

    }

    //当前任务列表
    private List<Task> getCurrentTaskList(String id) {
        List<Task> taskList = taskService.createTaskQuery().processInstanceId(id).list();

        return taskList;
    }

    /**
     * 查询待办
     * @param pageParam
     * @return
     */
    @Override
    public IPage<ProcessVo> findPending(Page<Process> pageParam) {
        //1.根据当前登录的用户名称,封装查询条件
        TaskQuery taskQuery = taskService.createTaskQuery()
                .taskAssignee(LoginUserInfoHelper.getUsername())
                .orderByTaskCreateTime()
                .desc();
        //2.调用方法分页条件查询,返回待办任务list集合
        int begin = (int) ((pageParam.getCurrent() - 1) * pageParam.getSize());
        int size = (int) (pageParam.getSize());
        List<Task> taskList = taskQuery.listPage(begin, size);
        //3.封装返回list集合到List<ProcessVo>中
        List<ProcessVo> processVoList = new ArrayList<>();
        for (Task task : taskList) {
            //从task获取业务key
            long businessKey = Long.parseLong(task.getBusinessKey());
            //用业务key获取Process对象
            Process process = baseMapper.selectById(businessKey);
            ProcessVo processVo = new ProcessVo();
            BeanUtils.copyProperties(process, processVo);
            processVo.setTaskId(task.getId());
            //添加到最终List集合中
            processVoList.add(processVo);

        }
        //4.封装返回的IPage对象
        IPage<ProcessVo> pageList = new Page<>(pageParam.getCurrent(), pageParam.getSize(), taskQuery.count());
        pageList.setRecords(processVoList);
        return pageList;
    }

    /**
     * 查看审批详情
     *
     * @param id
     * @return
     */
    @Override
    public Map<String, Object> show(Long id) {
        //1.根据流程id获取流程信息process
        Process process = baseMapper.selectById(id);
        //2.根据流程id获取流程记录信息
        LambdaQueryWrapper<ProcessRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ProcessRecord::getProcessId, id);
        List<ProcessRecord> recordList = processRecordService.list(wrapper);
        //3.根据模板id查询模板信息
        ProcessTemplate template = processTemplateService.getById(process.getProcessTemplateId());
        //4.判断当前用户是否可以审批
        boolean isApprove = false;
        String currentUser = LoginUserInfoHelper.getUsername();
        List<Task> taskList = this.getCurrentTaskList(process.getProcessInstanceId());
        for (Task task : taskList) {
            if (task.getAssignee().equals(currentUser)) {
                isApprove = true;
            }
        }

        //5.查询数据封装到map集合,返回
        Map<String, Object> map = new HashMap<>();
        map.put("isApprove", isApprove);
        map.put("process", process);
        map.put("processRecordList", recordList);
        map.put("processTemplate", template);
        return map;
    }

    @Override
    public void approve(ApprovalVo approvalVo) {
        //1.从approvalVo获取任务id,根据任务id获取流程变量
        String taskId = approvalVo.getTaskId();
        Map<String, Object> variables = taskService.getVariables(taskId);
        for (Map.Entry<String, Object> entry : variables.entrySet()) {
            System.out.println(entry.getKey());
            System.out.println(entry.getValue());
        }
        //2.判断审批状态值: 1通过,-1驳回
        if (approvalVo.getStatus() == 1) {
            //完成任务
            taskService.complete(taskId);
        } else {
            //结束流程
            this.endTask(taskId);
        }
        //3.记录审批相关过程信息oa_process_record
        String description = approvalVo.getStatus().intValue() == 1 ? "已通过" : "驳回";
        processRecordService.record(approvalVo.getProcessId(), approvalVo.getStatus(), description);
        //4.查询下一个审批人,更新流程表process的记录
        Process process = baseMapper.selectById(approvalVo.getProcessId());
        //查询任务
        List<Task> taskList = this.getCurrentTaskList(process.getProcessInstanceId());
        if (!CollectionUtils.isEmpty(taskList)) {
            List<String> assignList = new ArrayList<>();
            for (Task task : taskList) {
                String assignee = task.getAssignee();
                SysUser user = sysUserService.getByUsername(assignee);
                assignList.add(user.getName());
                //TODO 公众号推送消息
            }
            //更新process表流程消息
            process.setDescription("等待" + StringUtils.join(assignList.toArray(), ",") + "审批");
            process.setStatus(1);
        } else {
            if (approvalVo.getStatus().intValue() == 1) {
                process.setDescription("审批完成(通过)");
                process.setStatus(2);
            } else {
                process.setDescription("审批完成(驳回)");
                process.setStatus(-1);
            }
        }
        baseMapper.updateById(process);
    }

    /**
     * 结束流程
     */
    private void endTask(String taskId) {
        //1.根据任务id获取任务对象Task
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        //2.获取流程定义模型BpmnModel
        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        //3.获取结束流向节点
        List<EndEvent> endEventList = bpmnModel.getMainProcess().findFlowElementsOfType(EndEvent.class);
        if (CollectionUtils.isEmpty(endEventList)) {
            return;
        }
        FlowNode endFlowNode = endEventList.get(0);
        //4.当前流向节点
        FlowNode currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(task.getTaskDefinitionKey());
        //5.清理当前流动分享
        currentFlowNode.getOutgoingFlows().clear();
        //6.创建新流向
        SequenceFlow newSequenceFlow = new SequenceFlow();
        newSequenceFlow.setId("newSequenceFlow");
        newSequenceFlow.setSourceFlowElement(currentFlowNode);
        newSequenceFlow.setTargetFlowElement(endFlowNode);
        //7.当前节点指向新方向
        List newSequenceFlowList = new ArrayList();
        newSequenceFlowList.add(newSequenceFlow);
        //指向
        currentFlowNode.setOutgoingFlows(newSequenceFlowList);
        //8.完成当前任务
        taskService.complete(taskId);
    }

    /**
     * 已处理
     *
     * @param pageParam
     * @return
     */
    @Override
    public IPage<ProcessVo> findProcessed(Page<Process> pageParam) {
        //封装查询条件
        HistoricTaskInstanceQuery finished = historyService
                .createHistoricTaskInstanceQuery()
                .taskAssignee(LoginUserInfoHelper.getUsername())
                .finished();
        //查询后返回list集合
        int begin = (int) ((pageParam.getCurrent() - 1) * pageParam.getSize());
        int size = (int) pageParam.getSize();
        List<HistoricTaskInstance> finishedTaskList = finished.listPage(begin, size);
        //遍历list集合,封装List<ProcessVo>
        ArrayList<ProcessVo> processVoList = new ArrayList<>();
        for (HistoricTaskInstance finishedTask : finishedTaskList) {
            //流程实例id
            String processInstanceId = finishedTask.getProcessInstanceId();
            //根据流程实例id获取process信息
            LambdaQueryWrapper<Process> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Process::getProcessInstanceId, processInstanceId);
            //获得已处理任务对应的process
            Process process = baseMapper.selectOne(wrapper);
            //转为vo
            ProcessVo processVo = new ProcessVo();
            BeanUtils.copyProperties(process, processVo);
            processVoList.add(processVo);
        }
        //封装为IPage返回
        IPage<ProcessVo> pageList = new Page<>(pageParam.getCurrent(), pageParam.getSize(), finished.count());
        pageList.setRecords(processVoList);
        return pageList;
    }

    /**
     * 已发起
     *
     * @param pageParam
     * @return
     */
    @Override
    public IPage<ProcessVo> findStarted(Page<ProcessVo> pageParam) {
        ProcessQueryVo processQueryVo = new ProcessQueryVo();
        processQueryVo.setUserId(LoginUserInfoHelper.getUserId());
        IPage<ProcessVo> pageList = baseMapper.selectPage(pageParam, processQueryVo);
        return pageList;
    }
}
